package cn.elead.chaos.security.rest;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.reflections.Reflections;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.Environment;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.elead.chaos.core.util.StringUtils;
import cn.elead.chaos.framework.properties.ChaosProperties;
import cn.elead.chaos.framework.web.base.BaseApplication;
import cn.elead.chaos.framework.web.endpoint.EpomEndPoint;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

/**
 * <p>
 * 权限信息相关接口
 * </p>
 *
 * @author luopeng
 */
@RestController
@Api(tags = { "AuthEndpoint" }, description = "权限端点相关接口")
public class AuthEndpoint implements EpomEndPoint {

	private static List<Auth> list = new ArrayList<Auth>();

	private Environment environment;

	@Autowired
	public AuthEndpoint(Environment environment) {
		this.environment = environment;
	}

	/**
	 * 查询权限信息
	 */
	@ApiOperation("查询权限信息")
	@GetMapping("/web/security/auths")
	public List<Auth> findAll() {
		if (ObjectUtil.isEmpty(list)) {
			String basePackages = environment.getProperty(ChaosProperties.PREFIX + ".security.basePackages", BaseApplication.basePackage());
			list.addAll(getRequestMappingMethod(basePackages));
		}
		return list;
	}

	/**
	 * 查询权限信息
	 */
	@ApiOperation("查询权限信息")
	@GetMapping("/web/security/auth")
	public List<Auth> findPermissionsByName(String name) {
		if (ObjectUtil.isEmpty(list)) {
			findAll();
		}
		if (ObjectUtil.isNotEmpty(list) && StrUtil.isNotBlank(name)) {
			return list.stream().filter(a -> StrUtil.containsAny(a.getAuthName(), name) || StrUtil.containsAny(a.getAuthUniqueMark(), name)).collect(Collectors.toList());
		}
		return list;
	}

	/**
	 * @param scanPackage 需要扫描的包路径
	 */
	private List<Auth> getRequestMappingMethod(String scanPackage) {
		// 设置扫描路径
		Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(scanPackage)).setScanners(new MethodAnnotationsScanner()));

		// 扫描包内带有@PreAuthorize注解的所有方法集合
		Set<Method> methods = reflections.getMethodsAnnotatedWith(PreAuthorize.class);
		List<Auth> list = new ArrayList<>();
		// 循环获取方法
		methods.forEach(method -> {

			// 用于保存方法的请求类型
			String methodType = "";

			String authUrl = "";
			// 获取类上的@RequestMapping注解的值，作为请求的基础路径
			RequestMapping requestMapping = AnnotationUtils.findAnnotation(method.getDeclaringClass(), RequestMapping.class);
			if (ObjectUtil.isNotEmpty(requestMapping) && ObjectUtil.isNotEmpty(requestMapping.value())) {
				authUrl = StrUtil.addPrefixIfNot(requestMapping.value()[0], StrUtil.SLASH);
			}
			// 获取方法上的@PutMapping,@GetMapping,@PostMapping,@DeleteMapping注解的值，作为请求路径,并区分请求方式
			if (method.getAnnotation(PutMapping.class) != null) {
				methodType = "PUT";
				if (method.getAnnotation(PutMapping.class).value().length > 0) {
					authUrl += StrUtil.addPrefixIfNot(method.getAnnotation(PutMapping.class).value()[0], StrUtil.SLASH);
				}
			} else if (method.getAnnotation(GetMapping.class) != null) {
				methodType += "GET";
				if (method.getAnnotation(GetMapping.class).value().length > 0) {
					authUrl += StrUtil.addPrefixIfNot(method.getAnnotation(GetMapping.class).value()[0], StrUtil.SLASH);
				}
			} else if (method.getAnnotation(PostMapping.class) != null) {
				methodType = "POST";
				if (method.getAnnotation(PostMapping.class).value().length > 0) {
					authUrl += StrUtil.addPrefixIfNot(method.getAnnotation(PostMapping.class).value()[0], StrUtil.SLASH);
				}
			} else if (method.getAnnotation(DeleteMapping.class) != null) {
				methodType = "DELETE";
				if (method.getAnnotation(DeleteMapping.class).value().length > 0) {
					authUrl += StrUtil.addPrefixIfNot(method.getAnnotation(DeleteMapping.class).value()[0], StrUtil.SLASH);
				}
			}

			// 使用Auth对象来保存值
			Auth auth = new Auth();
			auth.setMethodType(methodType);

			// @ss.hasPermi('user:get121')
			String value = method.getAnnotation(PreAuthorize.class).value();
			value = StrUtil.subBetween(value, "('", "')");

			auth.setAuthUniqueMark(value);
			auth.setAuthUrl(authUrl);

			String apiName = "";
			String apiEnabled = environment.getProperty(ChaosProperties.PREFIX + ".security.api");
			if (StringUtils.isBlank(apiEnabled) || StringUtils.equals(apiEnabled, "true")) {
				Api api = method.getDeclaringClass().getAnnotation(Api.class);
				if (ObjectUtil.isNotEmpty(api)) {
					apiName = api.value() + "-";
				}
			}
			ApiOperation apiOperation = AnnotationUtils.findAnnotation(method, ApiOperation.class);
			if (ObjectUtil.isNotEmpty(apiOperation)) {
				auth.setAuthName(apiName + apiOperation.value());
			}
			list.add(auth);
		});
		return list;
	}
}
